package top.zhanglingxi.controller;

import cn.hutool.core.text.csv.*;
import cn.hutool.core.util.CharsetUtil;
import lombok.NonNull;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import top.zhanglingxi.algorithms.IGenerateLabyrinth;
import top.zhanglingxi.algorithms.Labyrinth;
import top.zhanglingxi.algorithms.Point;
import top.zhanglingxi.algorithms.PrimGenerateLabyrinth;
import top.zhanglingxi.domain.req.GenerateLabyrinthReq;
import top.zhanglingxi.enums.PointEnum;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 生成迷宫Controller
 *
 * @author ZWX
 */
@RestController
@RequestMapping("/generate/labyrinth")
public class GenerateLabyrinthController {

    public static Labyrinth labyrinth;

    /**
     * 生成迷宫
     *
     * @param req 迷宫生成参数
     * @return 迷宫
     */
    @GetMapping
    public Map<String, Object> generateLabyrinth(@Valid GenerateLabyrinthReq req) {
        IGenerateLabyrinth prim = new PrimGenerateLabyrinth();
        Point[][] points = prim.generateLabyrinth(req.getLength(), req.getWidth());

        labyrinth = new Labyrinth(req.getLength(), req.getWidth());
        labyrinth.setPoints(points);

        HashMap<String, Object> res = new HashMap<>(2);
        res.put("code", 200);
        res.put("data", points);
        return res;
    }

    /**
     * 读取csv文件生成迷宫
     *
     * @param file csv文件
     * @return 迷宫
     */
    @PostMapping("/upload/csv")
    public Map<String, Object> csv2Labyrinth(MultipartFile file) throws IOException {
        InputStreamReader isr = new InputStreamReader(file.getInputStream());
        BufferedReader br = new BufferedReader(isr);
        CsvReader reader = CsvUtil.getReader();
        CsvData csvData = reader.read(br);
        List<CsvRow> rows = csvData.getRows();
        int length = rows.size();
        int width = rows.get(0).size();
        Point[][] points = new Point[length][width];
        for (int i = 0; i < rows.size(); i++) {
            for (int j = 0; j < rows.get(i).size(); j++) {
                String type = rows.get(i).get(j).trim().toUpperCase();
                type = type.replace("\ufeff", "");
                if ("GREY".equals(type)) {
                    points[i][j] = new Point(i, j, PointEnum.GREY);
                } else if ("WHITE".equals(type)) {
                    points[i][j] = new Point(i, j, PointEnum.WHITE);
                } else if ("RED".equals(type)) {
                    points[i][j] = new Point(i, j, PointEnum.RED);
                } else if ("GREEN".equals(type)) {
                    points[i][j] = new Point(i, j, PointEnum.GREEN);
                }
            }
        }
        labyrinth = new Labyrinth(length, width);
        labyrinth.setPoints(points);

        HashMap<String, Object> res = new HashMap<>(2);
        res.put("code", 200);
        res.put("data", points);
        return res;
    }

    /**
     * 下载迷宫 csv格式
     *
     * @param response 响应
     */
    @GetMapping("/download/csv")
    public void download2Csv(HttpServletResponse response) throws IOException {
        response.setContentType("application/csv");
        response.setHeader("Pragma", "public");
        response.setHeader("Cache-Control", "max-age=30");
        response.setHeader("Content-Disposition", "attachment; filename=" + System.currentTimeMillis() + ".csv");

        ServletOutputStream os = response.getOutputStream();
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os, CharsetUtil.CHARSET_UTF_8));
        CsvWriter writer = CsvUtil.getWriter(bw);
        @NonNull Point[][] points = labyrinth.getPoints();
        for (Point[] point : points) {
            String[] items = Arrays.stream(point).map(Point::getType).map(Enum::toString).toArray(String[]::new);
            writer.writeLine(items);
        }
        writer.flush();
        writer.close();
    }
}
